from deepface import DeepFace
import numpy as np
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

MODEL_NAME = 'VGG-Face'

def represent_face(image_path: str) -> np.ndarray | None:
    """
    Extracts a facial embedding vector from a given image file.
    """
    import os
    from PIL import Image

    # Validate image file exists and is readable
    if not os.path.exists(image_path):
        logger.error(f"Image file does not exist: {image_path}")
        raise FileNotFoundError(f"Image file not found: {image_path}")

    if os.path.getsize(image_path) == 0:
        logger.error(f"Image file is empty: {image_path}")
        raise ValueError(f"Image file is empty: {image_path}")

    # Try to open and validate the image with PIL first
    try:
        with Image.open(image_path) as img:
            # Verify it's a valid image
            img.verify()
            logger.info(f"Image validation successful: {image_path}, format: {img.format}, size: {img.size}")
    except Exception as e:
        logger.error(f"Invalid image file {image_path}: {e}")
        raise ValueError(f"Invalid image file: {e}")

    try:
        logger.info(f"Starting face embedding extraction from {image_path}")
        embedding_objs = DeepFace.represent(
            img_path=image_path,
            model_name=MODEL_NAME,
            enforce_detection=False  # 临时设置为False以便测试
        )
        if embedding_objs and len(embedding_objs) > 0:
            embedding = embedding_objs[0]['embedding']
            logger.info(f"Successfully extracted embedding from {image_path}, vector length: {len(embedding)}")
            return np.array(embedding, dtype=np.float32)
        else:
            logger.warning(f"No face detected in {image_path}")
            return None
    except Exception as e:
        logger.error(f"DeepFace processing failed for {image_path}. Error: {e}")
        # Re-raise the exception to be caught by the calling function
        raise e

def verify_face(image_path: str, stored_embedding: np.ndarray) -> bool:
    """
    Verifies if the face in the new image matches the stored embedding by calculating cosine distance.
    """
    try:
        # 1. Generate embedding for the new image
        new_embedding_obj = represent_face(image_path)
        
        if new_embedding_obj is None:
            logger.warning(f"Could not generate embedding for verification image {image_path}.")
            return False

        # 2. Calculate cosine distance using numpy
        a = stored_embedding
        b = new_embedding_obj
        distance = 1 - (np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

        # 3. Compare with threshold
        # The default threshold for VGG-Face model with cosine distance is 0.40.
        # We are increasing it to 0.60 to be more tolerant in real-world conditions.
        # This adjustment is based on testing results showing that same-person verification
        # was failing with distances around 0.55-0.57.
        threshold = 0.60
        is_match = distance <= threshold
        
        logger.info(f"Verification for '{image_path}': distance={distance:.4f}, threshold={threshold}, match={is_match}")
        
        return is_match

    except Exception as e:
        logger.error(f"An unexpected error occurred during face verification for {image_path}: {e}")
        return False
